<?php
/**
 *  
 */
namespace TwinPeaks\Core;

abstract class CController
{
	use TAppInjector;
	
	/**
	 * @var CFrontController
	 */
	private $fcInstance;

	/**
	 * @var string
	 */
	private $methodName;
	
	/**
	 * @var array
	 */
	private $methodParams;
	
	/**
	 * @var string Name of method handling errors
	 */
	private $errorHandlerName;
	
	/**
	 * @var array
	 */
	private $errors = [];
	
	/**
	 * @var CLayout Page layout
	 */
	private $pageLayout = null;
	
	/**
	 * @return void
	 */
	function __construct($methodName, $methodParams = [])
	{
		if (!method_exists($this, $methodName))
			CSysException::controllerNoMethod($this, $methodName)->_throw();
		
		$this->methodName = $methodName;
		$this->methodParams = $methodParams;		
		$this->errorHandlerName  = '__' . $this->methodName . 'Error';
	}
	
	/**
	 * @return void
	 */
	final function setFrontController($instance)
	{
		$this->fcInstance = $instance;
	}
	
	/**
	 * @return CFrontController
	 */
	final function getFrontController()
	{
		return $this->fcInstance;
	}
	
	/**
	 * @return string
	 */
	final function getMethodName()
	{
		return $this->methodName;
	}
	
	/**
	 * @return array
	 */
	final function getMethodParams()
	{
		return $this->methodParams;
	}
	
	/**
	 * @return CFilter
	 */
	function getFilter()
	{
		return $this->getFrontController()->getFilter();
	}
	
	/**
	 * @return boolean 
	 */
	function checkUserRights($rule = null)
	{
		return true;
	}
	
	/**
	 * @return boolean
	 */
	final function hasErrors()
	{
		return (boolean) count($this->errors);
	}
	
	/**
	 * @return void
	 */
	final function addError($errId)
	{
		$this->errors[] = $errId;
	}

	/**
	 * @return mixed 
	 */
	final function execute()
	{
		try
		{
			$app = self::getApplication();
			$cascade = $app->getCascade();
			$reverseCascade = $app->getReverseCascade();
			
			if (!$app->getOption(OPT_NO_ACCESS_CONTROLL))
			{
				$rule = $app->getCurrentRule();				
				// Check user rights.
				cascade_invoc($cascade, 'checkUserRights', [$rule]);
			}

			// Create a page layout using the cascading invocation.
			$this->pageLayout = cascade_invoc($reverseCascade, 'createPageLayout');
			
			$result = call_user_func_array([$this, $this->getMethodName()],
				$this->getMethodParams());
			
			if ($this->hasErrors())
				call_user_func([$this, $this->errorHandlerName]);
		}
		catch (CException $excep)
		{
			$excep->_throw(); // Re-throw exception
		}
		return $result;
	}
	
	/**
	 * @return CLayout|false
	 */
	function createPageLayout()
	{
		return null;
	}
	
	/**
	 * @return CLayout|null
	 */
	function getPageLayout()
	{
		return $this->pageLayout;
	}
	
	/**
	 * @return void
	 */
	function redirect($loc, $code = 303)
	{
		$app = self::getApplication();
		if (is_string($loc))
			$loc = Http\CUri::createFromString($loc);
		if (!$loc->isAbsolute())
			$loc = Http\CUri::merge($app->getRequestURI(), $loc);
		$app->getResponse()->redirect($loc, $code);
	}
}
